package com.danicsoft.daide.token;

import java.io.IOException;
import java.io.OutputStream;


/**
 * A token that is not a text or integer token. It has a type and a subtype. Its
 * type is something like COMMAND and its subtype is something like NME.
 * 
 * @author Daniel Yule (daniel.yule@gmail.com)
 * @version 1.0
 */
public class StandardToken extends Token implements CommonToken {

	/**
	 * The subtype of this token
	 */
	private byte data;

	/**
	 * The mapping to use to retrieve string information of this token.
	 */
	private TokenMap mapper;





	/**
	 * Consutrcts a new <code>StandardToken</code> of the specified type and
	 * subtype.
	 * 
	 * @param type
	 *        The type of this token.
	 * @param data
	 *        The subtype of this token.
	 * @param mapper
	 *        The mapping to use for this token.
	 */
	StandardToken(byte type, byte data, TokenMap mapper) {
		super(type);
		this.data = data;
		this.mapper = mapper;
	}


	@Override
	public Byte getData() {
		return data;
	}

	@Override
	public int hashCode() {
		return getOutput();
	}

	/**
	 * Gets the output for this token.
	 * 
	 * @return A short representation of this token.
	 */
	public short getOutput() {
		return (short) (getType() << 8 | data);
	}

	@Override
	public String toString() {
		try {
			return mapper.convert(this);
		}
		catch (InvalidTokenException e) {
			return "UNKNOWN";
		}
	}

	@Override
	public void output(OutputStream output) throws IOException {
		output.write(getType());
		output.write(data);

	}

	/**
	 * Checks to see if this token matches the token derived from the given
	 * string.
	 * 
	 * @param str
	 *        The string to compare
	 * @return True if it matches.
	 */
	public boolean matchesString(String str) {
		try {
			return mapper.convert(str).equals(this);
		}
		catch (InvalidTokenException e) {
			return false;
		}

	}

	@Override
	public Token clone() {
		return new StandardToken(getType(), data, mapper);
	}

	/**
	 * Checks if this token matches the given type and subtype.
	 * 
	 * @param type
	 *        The type of the token to check.
	 * @param subType
	 *        The subtype of the token to check.
	 * @return True if the token matches, false otherwise.
	 */
	public boolean matches(byte type, byte subType) {
		return this.getType() == type && this.data == subType;
	}

	public byte getSubType() {
		return getData();
	}

}
